﻿using System;
using System.Collections.Generic;

using System.Text;
using AuroraLightsFX.Properties;
using System.IO;
using System.Xml;

namespace AuroraLightsFX
{
public class LEDcontrol : USBDevice
{
    public delegate void SetPercentValueDelegate(decimal percent);
    public enum FirmwareLocation : byte
    {
        BINFile = 0xf2,
        EEPROM = 0xf1,
        Unknown = 0
    }

    public enum DeviceStatus
    {
        Busy = 0x11,
        Ready = 0x10,
        UnsupportedCommand = 0x12
    }
    public enum ResetModifiers : byte
    {
        All_Lights_Off = 3,
        Leave_Lights_On = 4,
        Sleep_Lights_Only = 2,
        User_Contorls_Lighted = 1
    }

 


    // Fields
    private const uint EE_DEF_SCHEME_START_LOC = 1;
    private const uint EE_FIRMWARE_START_LOC = 0;
    private const uint EE_MODEL_NUMBER_LOC = 3;
    private const uint EE_SERIAL_NUMBER_LOC = 4;
    private int LastErrorCode;
    private string LastErrorDescription;
    private IntPtr m_hDeviceHandle;
    private int m_OldProductId;
    public int ProductId;
    private const byte TOKEN_FIRMWARE = 0;
    private const byte TOKEN_MODEL = 3;
    private const byte TOKEN_POWERON = 1;
    private const byte TOKEN_SN = 4;
    private const byte TOKEN_STNDBY = 2;
    private const byte TOKEN_TEST = 5;
    internal string USBDevicePath;
    public int VendorId;

    // Methods
    public LEDcontrol()
    {
        this.VendorId = 0x187c;
        this.ProductId = 0x511;
        this.m_OldProductId = 0x3410;
        this.m_hDeviceHandle = IntPtr.Zero;
        this.USBDevicePath = "";
        this.LastErrorCode = 0;
        this.LastErrorDescription = "";
    }

    public LEDcontrol(int nVendorId, int nProductId)
    {
        this.VendorId = 0x187c;
        this.ProductId = 0x511;
        this.m_OldProductId = 0x3410;
        this.m_hDeviceHandle = IntPtr.Zero;
        this.USBDevicePath = "";
        this.LastErrorCode = 0;
        this.LastErrorDescription = "";
        this.VendorId = nVendorId;
        this.ProductId = nProductId;
    }

    public void CloseDevice()
    {
        if (this.m_hDeviceHandle != IntPtr.Zero)
        {
            USBDevice.CloseDevice(this.m_hDeviceHandle);
            this.m_hDeviceHandle = IntPtr.Zero;
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        this.CloseDevice();
    }

    public bool EEpromRead(byte token, uint iaddr, uint len, byte[] inbuf)
    {
        return this.EEpromRead(token, iaddr, len, inbuf, null);
    }

    public bool EEpromRead(byte token, uint iaddr, uint len, byte[] inbuf, SetPercentValueDelegate SetPercentValue)
    {
        bool flag = true;
        uint num = 0;
        uint num2 = len / 8;
        uint num3 = len % 8;
        USBaccess baccess = new USBaccess();
        string versionNumber = "";
        this.GetFirmwareVersion(out versionNumber);
        if ((Convert.ToInt32(versionNumber) <= 0x2717) && (token == 0))
        {
            token = 5;
        }
        if ((len > 0) && (len < 8))
        {
            num2 = 1;
        }
        else if (num3 > 0)
        {
            num2++;
        }
        decimal num4 = num2;
        while (num2 > 0)
        {
            flag = this.EEpromReadBytes(token, iaddr);
            if (!flag)
            {
                return flag;
            }
            if (Convert.ToInt32(versionNumber) <= 0x2717)
            {
                baccess.GetStatus();
            }
            else
            {
                baccess.GetData();
            }
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[1];
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[2];
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[3];
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[4];
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[5];
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[6];
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[7];
            if (num >= len)
            {
                return flag;
            }
            inbuf[num++] = baccess.buf[8];
            iaddr += 8;
            num2--;
            if (SetPercentValue != null)
            {
                SetPercentValue((num4 - num2) / num4);
            }
        }
        return flag;
    }

    private bool EEpromReadBytes(byte token, uint iaddr)
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 10;
        abReport[2] = token;
        abReport[3] = (byte) ((iaddr & 0xff00) >> 8);
        abReport[4] = (byte) (iaddr & 0xff);
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool EEpromWrite(byte token, uint iaddr, int len, byte[] outbuf)
    {
        return this.EEpromWrite(token, iaddr, len, outbuf, null);
    }

    public bool EEpromWrite(byte token, uint iaddr, int len, byte[] outbuf, SetPercentValueDelegate SetPercentValue)
    {
        bool flag = true;
        uint index = 0;
        int num2 = 0;
        int num3 = 0;
        if ((len > 0) && (len <= 8))
        {
            num2 = 1;
        }
        else if (len > 8)
        {
            num2 = len / 8;
            num3 = len % 8;
        }
        if (num3 > 0)
        {
            num2++;
        }
        decimal num4 = num2;
        while (num2 > 0)
        {
            flag = this.EEpromWriteStart(token, iaddr);
            if (flag)
            {
                this.SendEEpromData(outbuf, index);
            }
            else
            {
                flag = false;
            }
            index += 8;
            iaddr += 8;
            num2--;
            if (SetPercentValue != null)
            {
                SetPercentValue((num4 - num2) / num4);
            }
        }
        return flag;
    }

    public bool EEpromWriteFinished()
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 9;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    private bool EEpromWriteStart(byte token, uint iaddr)
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 8;
        abReport[2] = token;
        if (token == 5)
        {
            abReport[3] = (byte) ((iaddr & 0xff00) >> 8);
            abReport[4] = (byte) (iaddr & 0xff);
        }
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool GetCurrentEffect(ref byte[] arr)
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        bool flag = true;
        USBaccess baccess = new USBaccess();
        byte[] destinationArray = new byte[arr.Length];
        int destinationIndex = 0;
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        bool flag2 = false;
        while (((destinationIndex < arr.Length) && flag) && !flag2)
        {
            abReport[1] = 0x10;
            flag = USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength);
            if (flag)
            {
                baccess.GetStatus();
                if ((baccess.buf[1] == 0x10) && (baccess.buf[2] == 0))
                {
                    baccess.GetData();
                }
                flag2 = ((((baccess.buf[2] == 11) && (baccess.buf[3] == 10)) && ((baccess.buf[4] == 13) && (baccess.buf[5] == 15))) && ((baccess.buf[6] == 10) && (baccess.buf[7] == 12))) && (baccess.buf[8] == 14);
                if (!flag2)
                {
                    Array.Copy(baccess.buf, 1, destinationArray, destinationIndex, 8);
                    destinationIndex += 8;
                }
            }
        }
        arr = new byte[destinationIndex];
        Array.Copy(destinationArray, 0, arr, 0, destinationIndex);
        if (!flag)
        {
            this.SetError(-1, Resources.RecievingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool GetFirmwareLocation(out FirmwareLocation location)
    {
        location = FirmwareLocation.Unknown;
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 0x12;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            return false;
        }
        USBaccess baccess = new USBaccess();
        baccess.GetStatus();
        if ((baccess.buf[1] == 0x10) && (baccess.buf[2] == 0))
        {
            USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength);
            baccess.GetData();
        }
        bool status = baccess.status;
        if (status)
        {
            if (Enum.IsDefined(typeof(FirmwareLocation), baccess.buf[1]))
            {
                location = (FirmwareLocation) baccess.buf[1];
            }
            else
            {
                location = FirmwareLocation.Unknown;
            }
        }
        return status;
    }

    public bool GetFirmwareVersion(out string versionNumber)
    {
        bool status;
        versionNumber = "00000000";
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 11;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            return false;
        }
        USBaccess baccess = new USBaccess();
        baccess.GetStatus();
        if ((baccess.buf[1] != 0x10) && (baccess.buf[2] != 0))
        {
            status = baccess.status;
            if (status)
            {
                versionNumber = Encoding.ASCII.GetString(baccess.buf, 1, 8);
            }
            versionNumber = versionNumber.Replace("1", "100");
            return status;
        }
        USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength);
        baccess.GetData();
        status = baccess.status;
        if (status)
        {
            versionNumber = Encoding.ASCII.GetString(baccess.buf, 1, 8);
        }
        return status;
    }

    public int GetLastErrorCode()
    {
        return this.LastErrorCode;
    }

    public string GetLastErrorDescription()
    {
        return this.LastErrorDescription;
    }


    

    public bool GetSerialNumber(out string serialNumber)
    {
        serialNumber = "00000000";
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 13;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            return false;
        }
        USBaccess baccess = new USBaccess();
        baccess.GetStatus();
        if ((baccess.buf[1] == 0x10) && (baccess.buf[2] == 0))
        {
            USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength);
            baccess.GetData();
        }
        bool status = baccess.status;
        if (status)
        {
            serialNumber = string.Format("{0:X2} {1:X2} {2:X2} {3:X2} {4:X2} {5:X2} {6:X2} {7:X2}", new object[] { baccess.buf[1], baccess.buf[2], baccess.buf[3], baccess.buf[4], baccess.buf[5], baccess.buf[6], baccess.buf[7], baccess.buf[8] });
        }
        return status;
    }

    public DeviceStatus GetStatus()
    {
        USBaccess baccess = new USBaccess();
        baccess.GetStatus();
        DeviceStatus busy = DeviceStatus.Busy;
        if (baccess.buf != null)
        {
            busy = (DeviceStatus) baccess.buf[1];
        }
        LogManager.Log(LogManager.LogLevel.Info, "GetStatus function", "Status: " + busy);
        return busy;
    }

    public bool OpenDeviceIfNeeded()
    {
        return this.OpenDeviceIfNeeded(false);
    }

    public bool OpenDeviceIfNeeded(bool bforceOpenNewOne)
    {
        if (bforceOpenNewOne)
        {
            USBDevice.CloseDevice(this.m_hDeviceHandle);
            this.m_hDeviceHandle = IntPtr.Zero;
            this.USBDevicePath = "";
        }
        if (this.USBDevicePath == "")
        {
            if (this.VendorId == 0)
            {
                return false;
            }
            this.ProductId = 0x511;
            if (!USBDevice.FindDevice(this.VendorId, this.ProductId, out this.USBDevicePath))
            {
                if (!USBDevice.FindDevice(this.VendorId, this.m_OldProductId, out this.USBDevicePath))
                {
                    return false;
                }
                this.ProductId = this.m_OldProductId;
            }
        }
        if ((this.m_hDeviceHandle == IntPtr.Zero) || (this.m_hDeviceHandle.ToInt32() == -1))
        {
            this.m_hDeviceHandle = USBDevice.OpenDevice(this.USBDevicePath);
            if (this.m_hDeviceHandle.ToInt32() == -1)
            {
                this.m_hDeviceHandle = IntPtr.Zero;
            }
        }
        return (this.m_hDeviceHandle != IntPtr.Zero);
    }

    private bool ReadModel(out byte[] response)
    {
        response = new byte[8];
        uint iaddr = 3;
        for (int i = 0; i < response.Length; i++)
        {
            response[i] = 0;
        }
        if (!this.EEpromRead(3, iaddr, (uint) response.Length, response))
        {
            this.SetError(-1, Resources.RecievingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    internal bool ReadUSBData(byte dataID, out byte[] response)
    {
        response = null;
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = dataID;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            return false;
        }
        response = new byte[nReportLength];
        if (!USBDevice.ReceiveReport(this.m_hDeviceHandle, response, nReportLength))
        {
            this.SetError(-1, Resources.RecievingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool RebootRom()
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 12;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool SendCommand(byte[] Command)
    {
        uint nReportLength = 9;
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        if (Command.Length != nReportLength)
        {
            return false;
        }
        if (!USBDevice.SendReport(this.m_hDeviceHandle, Command, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool SendEEpromData(byte[] buf, uint index)
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        if (buf.Length <= index)
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        for (int i = 1; i < nReportLength; i++)
        {
            if (((index + i) - ((long) 1L)) < buf.Length)
            {
                abReport[i] = buf[(int) ((IntPtr) ((index + i) - ((long) 1L)))];
            }
            else
            {
                abReport[i] = 0;
            }
        }
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

   
    public bool SendReset()
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 7;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }



    ////public static bool SendVisualizationPacketsToEEprom(GroupPacket defLedsGroup, byte visualizationItemType)
    ////{

    ////    if (!LEDcontrol.SendSpecialReset(LEDcontrol.ResetModifiers.Leave_Lights_On, 0))
    ////    {
    ////        return false;
    ////    }
    ////    foreach (PacketData data in defLedsGroup)
    ////    {
    ////        GroupPacket packet;
    ////        try
    ////        {
    ////            packet = new GroupPacket(data);
    ////        }
    ////        catch (GroupPacketException exception)
    ////        {
    ////            LogManager.Log(AlienLabs.AlienFX.Tools.LogLevel.Info, "Creating Packet function", string.Concat(new object[] { "Packet Not Created", exception.CustomMessage, " -- ", DateTime.Now }));
    ////            break;
    ////        }
    ////        foreach (byte[] buffer in packet.GroupActionsInfoCommands)
    ////        {
    ////            if (buffer.Length != 9)
    ////            {
    ////                return false;
    ////            }
    ////            LogManager.Log(AlienLabs.AlienFX.Tools.LogLevel.Info, " Command sent to EEPROM ", string.Format("{0:x2} {1:x2} {2:x2} {3:x2} {4:x2} {5:x2} {6:x2} {7:x2} {8:x2}", new object[] { buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8] }));
    ////            byte[] send = this.CopyBytes(buffer, 1, 8);
    ////            if (!this.EEpromWrite(visualizationItemType, 0, buffer.Length - 1, send))
    ////            {
    ////                return false;
    ////            }
    ////        }
    ////    }
    ////    return this.sendEmptyVisualizationPackageToEEprom(visualizationItemType);
    ////}

    public bool SendSpecialReset(ResetModifiers resetModifier, int actionDuration)
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 7;
        abReport[2] = (byte) resetModifier;
        abReport[3] = (byte) ((actionDuration & 0xff00) >> 8);
        abReport[4] = (byte) (actionDuration & 0xff);
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool SendStart()
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 5;
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public bool SendTiming(int timing)
    {
        if (!this.OpenDeviceIfNeeded())
        {
            return false;
        }
        uint nReportLength = 9;
        byte[] abReport = new byte[nReportLength];
        abReport[0] = 0;
        abReport[1] = 14;
        abReport[2] = (byte) ((timing & 0xff00) >> 8);
        abReport[3] = (byte) (timing & 0xff);
        if (!USBDevice.SendReport(this.m_hDeviceHandle, abReport, nReportLength))
        {
            this.SetError(-1, Resources.SendingDataError);
            return false;
        }
        this.SetError(0, Resources.NoErrors);
        return true;
    }

    public void SetError(int nError, string sError)
    {
        this.LastErrorCode = nError;
        this.LastErrorDescription = sError;
    }
}

 

}
